﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using Microsoft.Xna.Framework.Graphics;   //   for Texture2D
using Microsoft.Xna.Framework;  //  for Vector2

namespace zombieArena
{
    class Map
    {
        private int height { get; set; }
        private int width { get; set; }
        public Rectangle[] ObstacleList { get; set; }
        public List<Bullet> bulletList { get; set; }
        private float viewHeight { get; set; }
        private float viewWidth { get; set; }
        private Texture2D texture { get; set; }
        public Rectangle viewPort { get; set; }
        public Vector2 screenPosition { get; set; }
        public Player player { get; set; }
        public Powerup powerup { get; set; }
        public Texture2D bulletTexture;
        public Texture2D laserTexture;

        public Texture2D[] zombieTextures;

        //Constants
        const int MAX_RANDOM = 180;
        const int POWERUP_FREQUENCY = 3;
        public const int TOTAL_ZOMBIES = 80;
        const int MAX_POWERUPS = 2;
        const int POINTS_FOR_EXTRA_LIFE = 3000;
        
        public bool extraLifeSound = false;

        // Map divided into a grid to hold enemies
        public List<Enemy>[,] enemyList;
        // size of each grid cell
        public int cellSize = 20;
        // size of the double array (arraySize by arraySize
        public int arraySize;
        // number of zombies
        int size = 100;
        // zombie step collision detection scaling
        float collisionScale = 2f;

        // number of zombies alive
        public int zombiesAlive = 0;
        public int zombiesKilled = 0;
        public int zombieCollisionCount = 0;
        public int bulletCollisionCount = 0;
        
        public int zombieInScreen = 0;
        public int zombiePerLevel = 0;
        public int level = 1;

        List<Powerup> removePowerup = new List<Powerup>();
        public List<Powerup> powerupList = new List<Powerup>();

        // Calls class variables which holds arrays of collision and respawn
        variables v;

        //Variables for the powerups
        Random rnd = new Random();
        public bool pickedUp = false;
        public int pickedUpID;

        public bool playerHit = false;

        // Animation stuff
        float timer = 0f; // keeps track of time
        float interval = 60f; // sets frame rate

        // optimization
        Vector2 enemyMovement;
        DateTime start;
        TimeSpan end;
        Bullet b;
        int checkRadius;
        int minX;
        int minY;
        int checkX;
        int checkY;
        Enemy enemy;
        Enemy currentEnemy;
        float distance;
        bool allowMovement;
        float x;
        float y;
        double playerZombieDistance;
        double afterMoveDistance;
        double beforeMoveDistance;
        float enemyPositionX;
        float enemyPositionY;
        float collsionRadius = 40;

        // Animation
        Animation animation;
        public List<List<Animation>> animationList;
        public List<Animation> deadZombieAnimations;
        public List<Animation> zombieBlurAnimations;
        public List<Animation> bulletAnimations;

        public Map(int viewWidth, int viewHeight, int width, int height, float initScreenX, float initScreenY, Texture2D map, ref Player player, ref Texture2D[] zombieTextures)
        {
            // initialize grid
            arraySize = 2000 / cellSize;
            enemyList = new List<Enemy>[arraySize, arraySize];

            this.zombieTextures = zombieTextures;

            v = new variables();
            

            for (int i = 0; i < arraySize; i++)
            {
                for (int j = 0; j < arraySize; j++)
                {
                    enemyList[i, j] = new List<Enemy>();
                }
            }

            this.width = width;
            this.height = height;
            this.viewHeight = viewHeight;
            this.viewWidth = viewWidth;

            this.player = player;

            viewPort = new Rectangle((int)player.position.X - viewWidth / 2, (int)player.position.Y - viewHeight / 2, (int)this.viewWidth, (int)this.viewHeight);

            texture = map;

            screenPosition = new Vector2(initScreenX, initScreenY);

            ObstacleList = v.ObstacleList;
            bulletList = new List<Bullet>();

            deadZombieAnimations = new List<Animation>();
            bulletAnimations = new List<Animation>();
            zombieBlurAnimations = new List<Animation>();
            animationList = new List<List<Animation>>();
            animationList.Add(deadZombieAnimations);
            animationList.Add(bulletAnimations);
            animationList.Add(zombieBlurAnimations);
        }

        public void draw(ref SpriteBatch spriteBatch)
        {
            
            // BOUDARY COLLISION DETECTION FOR MAP (NOT GO OUT OF BOUNDS)
            if ((((int)player.position.Y - viewHeight / 2) > 0 && ((int)player.position.Y + viewHeight / 2) < height))
                viewPort = new Rectangle(viewPort.X, (int)player.position.Y - (int)(viewHeight / 2), (int)this.viewWidth, (int)this.viewHeight);
            if (((int)player.position.X - viewWidth / 2) > 0 && ((int)player.position.X + viewWidth / 2) < width)
                viewPort = new Rectangle((int)player.position.X - (int)(viewWidth / 2), viewPort.Y, (int)this.viewWidth, (int)this.viewHeight);
            
           
            // GETTING THE SCREEN POSITION OF THE PLAYER
            //Vector2 playerscreenpos = player.position - new Vector2(viewPort.X, viewPort.Y);
           
            // PRINT COORDINATES OF THE MAP AND THE PLAYER
            //Console.WriteLine(player.position);
            //Console.WriteLine(viewPort.X + "," + viewPort.Y);

            //DRAW MAP
            spriteBatch.Draw(texture, screenPosition, viewPort, Color.White);

            //DRAW PLAYER
            //player.draw(spriteBatch, viewPort);
            //spriteBatch.Draw(player.charTexture, playerscreenpos, new Rectangle(40 * player.currentSprite, 56 * player.spriteRow, player.width, player.height), Color.White);
        }

      
        public bool movePlayer()
        {
            bool collision = false;
            float speed = 5;
            float x = player.moveDirection.X * speed;
            float y = player.moveDirection.Y * speed;

            /*
            for (int i = 0; i < ObstacleList.Length; i++)
            {
                if (ObstacleList[i].Contains((int)(player.position.X + player.width + x), (int)(player.position.Y + player.height/1.25 + y))) // Bottom right corner
                { collision = true; break; }
                if (ObstacleList[i].Contains((int)(player.position.X + x), (int)(player.position.Y + player.height/1.25 + y))) // Bottom Left corner
                { collision = true; break; }
            }*/

            // slide player along obstacles
            /*
            for (int i = 0; i < ObstacleList.Length; ++i)
            {
                zombieCollisionCount++;
                if (ObstacleList[i].Contains((int)(player.position.X + player.width + x), (int)(player.position.Y + player.height / 1.25))) // Bottom right corner
                { x = 0; }
                if (ObstacleList[i].Contains((int)(player.position.X + x), (int)(player.position.Y + player.height / 1.25))) // Bottom Left corner
                { x = 0; }
                if (ObstacleList[i].Contains((int)(player.position.X + player.width), (int)(player.position.Y + player.height / 1.25 + y))) // Bottom right corner
                { y = 0; }
                if (ObstacleList[i].Contains((int)(player.position.X), (int)(player.position.Y + player.height / 1.25 + y))) // Bottom Left corner
                { y = 0; }
            }*/

            for (int i = 0; i < ObstacleList.Length; ++i)
            {
                zombieCollisionCount++;
                if (ObstacleList[i].Contains((int)(player.position.X + player.width / 2 + x), (int)(player.position.Y + player.height / 2))) // Bottom right corner
                { x = 0; }
                if (ObstacleList[i].Contains((int)(player.position.X - player.width / 2 + x), (int)(player.position.Y + player.height / 2))) // Bottom Left corner
                { x = 0; }
                if (ObstacleList[i].Contains((int)(player.position.X + player.width / 2 + x), (int)(player.position.Y - player.height / 8))) // Top right corner
                { x = 0; }
                if (ObstacleList[i].Contains((int)(player.position.X - player.width / 2 + x), (int)(player.position.Y - player.height / 8))) // Top Left corner
                { x = 0; }

                if (ObstacleList[i].Contains((int)(player.position.X + player.width / 2), (int)(player.position.Y + player.height / 2 + y))) // Bottom right corner
                { y = 0; }
                if (ObstacleList[i].Contains((int)(player.position.X - player.width / 2), (int)(player.position.Y + player.height / 2 + y))) // Bottom Left corner
                { y = 0; }
                if (ObstacleList[i].Contains((int)(player.position.X + player.width / 2), (int)(player.position.Y - player.height / 8 + y))) // Top right corner
                { y = 0; }
                if (ObstacleList[i].Contains((int)(player.position.X - player.width / 2), (int)(player.position.Y - player.height / 8 + y))) // Top Left corner
                { y = 0; }
            }

            if (player.position.X + x < 30)
                x = 0;
            if (player.position.X + x > 1600 - player.width)
                x = 0;

            if (player.position.Y + y < 50)
                y = 0;
            if (player.position.Y + y > 1200 - player.height/3)
                y = 0;

            if (!collision)
                player.position += new Vector2(x, y);

            checkPowerupCollision();

            return collision;
        }

        public void newLevel()
        {
            zombiesAlive = 0;
            zombiePerLevel = 200;
            zombieInScreen = 20;
            clearEnemies();
            bulletList.Clear();
        }

        // add zombies to the map
        public void addEnemy(ref GraphicsDeviceManager graphics, ref Texture2D t, int round)
        {
            // clear map of zombies
            // zombiesAlive = 200;
            int arrayPos = rnd.Next(v.respawnPositions.Length);
            Vector2 xyCoord = v.respawnPositions[arrayPos];

            if (enemyList[(int)xyCoord.X, (int)xyCoord.Y].Count() == 0 && zombiesAlive < TOTAL_ZOMBIES)
            {
                int type;

                //Spawning of enemies done by randomizing a value with the round number
                if (rnd.Next(1, round) % 4 == 0)
                    type = 2;
                else if (rnd.Next(1, round) % 7 == 0)
                    type = 3;
                else
                    type = 1;


                Enemy e = new Enemy((int)xyCoord.X * cellSize, (int)xyCoord.Y * cellSize, 80, 56, zombieTextures[rnd.Next(5)], type);

                enemyList[(int)xyCoord.X, (int)xyCoord.Y].Add(e);
                zombiesAlive++;
            }

        }

        // clear map of zombies
        public void clearEnemies()
        {
            zombiesAlive = 0;

            for (int i = 0; i < arraySize; i++)
            {
                for (int j = 0; j < arraySize; j++)
                {
                    enemyList[i, j].Clear();
                }
            }
        }

        public float moveEnemies(ref SpriteBatch spriteBatch, ref bool freezeZombies, ref GameTime gameTime)
        {
            start = DateTime.Now;
            timer += gameTime.ElapsedGameTime.Milliseconds;

            zombieCollisionCount = 0;
            // move all zombies

            for (int i = 0; i < arraySize; ++i)
            {
                for (int j = 0; j < arraySize; ++j)
                {
                    int count = 0;
                    while (count < enemyList[i, j].Count)
                    {
                        enemy = enemyList[i, j][count];

                        // check if the enemy already moved to a higher cell to prevent double movement
                        if(enemy.state == "MOVED")
                        {
                            enemy.state = "ALIVE";
                            count++;
                            continue;
                        }

                        // flag to check if zombie should be allowed to move (zombie to zombie collision)
                        allowMovement = true;

                        // Normalized Vector between zombie and player
                        //Vector2 enemyMovement = new Vector2(player.position.X - enemy.position.X, player.position.Y - enemy.position.Y);
                        enemyMovement = player.position;
                        enemyMovement.X -= enemy.position.X;
                        enemyMovement.Y -= enemy.position.Y;
                        enemyMovement.Normalize();
                        enemy.velocity = enemyMovement;

                        // Zombie sprite
                        // check if timer is more than the chosen interval for sprite animation
                        //timer += gameTime.ElapsedGameTime.Milliseconds;
                        if (timer > (interval))
                        {
                            enemy.currentSprite = (enemy.currentSprite + 1) % 3;
                            //timer = 0f;
                        }
                        if (enemyMovement.Y >= 0.5)
                        {
                            enemy.spriteRow = 0;
                        }
                        else if (enemyMovement.Y <= -0.5)
                        {
                            enemy.spriteRow = 1;
                        }
                        else if (enemyMovement.X <= -0.5)
                        {
                            enemy.spriteRow = 2;
                        }
                        else if (enemyMovement.X >= 0.5)
                        {
                            enemy.spriteRow = 3;
                        }
                        // red flash
                        enemy.updateColor();
                        
                        
                        // Get X and Y values of movement vector
                        x = enemyMovement.X * enemy.speed;
                        y = enemyMovement.Y * enemy.speed;

                        // collision detection with player
                        playerZombieDistance = Math.Sqrt(Math.Pow(enemy.position.X - player.position.X - (x * collisionScale), 2) + Math.Pow(enemy.position.Y - player.position.Y - (y * collisionScale), 2.0));
                        if (playerZombieDistance < 20)
                        {
                            playerHit = true;
                            allowMovement = false;
                        }

                        float tempX = x;
                        float tempY = y;
                        // check cell zombie is in, and all surrounding cells if it didn't collide with an obstacle
                        while(!freezeZombies && allowMovement)
                        {
                            // check all cells around zombie                      
                            if (allowMovement)
                                allowMovement = checkCell(i, j, x, y, enemy);
                            if (allowMovement)
                                allowMovement = checkCell(i + 1, j, x, y, enemy);
                            if (allowMovement)
                                allowMovement = checkCell(i - 1, j, x, y, enemy);
                            if (allowMovement)
                                allowMovement = checkCell(i, j + 1, x, y, enemy);
                            if (allowMovement)
                                allowMovement = checkCell(i, j - 1, x, y, enemy);
                            if (allowMovement)
                                allowMovement = checkCell(i + 1, j + 1, x, y, enemy);
                            if (allowMovement)
                                allowMovement = checkCell(i + 1, j - 1, x, y, enemy);
                            if (allowMovement)
                                allowMovement = checkCell(i - 1, j + 1, x, y, enemy);
                            if (allowMovement)
                                allowMovement = checkCell(i - 1, j - 1, x, y, enemy);

                            if (allowMovement == false)
                            {
                                if (x != 0 && tempY != 0)
                                {
                                    tempX = enemyMovement.X;
                                    enemyMovement.X = 0;
                                    x = 0;
                                    y = enemyMovement.Y * enemy.speed;
                                    allowMovement = true;
                                }
                                else if (y != 0)
                                {
                                    enemyMovement.X = tempX;
                                    enemyMovement.Y = 0;
                                    y = 0;
                                    x = enemyMovement.X * enemy.speed;
                                    allowMovement = true;
                                    tempY = 0;
                                }
                                else
                                {
                                    allowMovement = false;
                                    break;
                                }
                            }
                            else
                                break;
                        }

                        if(freezeZombies)
                        {
                            allowMovement = false;
                        }

                        // if the zombie's movement does not collide with another zombie
                        if (allowMovement)
                        {
                            // check for collision detection with obstacles
                            for (int ii = 0; ii < ObstacleList.Length; ++ii)
                            {
                                zombieCollisionCount++;
                                if (ObstacleList[ii].Contains((int)(enemy.position.X + enemy.width / 2 + x), (int)(enemy.position.Y + enemy.height / 2))) // Bottom right corner
                                { x = 0; }
                                if (ObstacleList[ii].Contains((int)(enemy.position.X - enemy.width / 2 + x), (int)(enemy.position.Y + enemy.height / 2))) // Bottom Left corner
                                { x = 0; }
                                if (ObstacleList[ii].Contains((int)(enemy.position.X + enemy.width / 2 + x), (int)(enemy.position.Y - enemy.height / 8))) // Top right corner
                                { x = 0; }
                                if (ObstacleList[ii].Contains((int)(enemy.position.X - enemy.width / 2 + x), (int)(enemy.position.Y - enemy.height / 8))) // Top Left corner
                                { x = 0; }

                                if (ObstacleList[ii].Contains((int)(enemy.position.X + enemy.width / 2), (int)(enemy.position.Y + enemy.height / 2 + y))) // Bottom right corner
                                { y = 0; }
                                if (ObstacleList[ii].Contains((int)(enemy.position.X - enemy.width / 2), (int)(enemy.position.Y + enemy.height / 2 + y))) // Bottom Left corner
                                { y = 0; }
                                if (ObstacleList[ii].Contains((int)(enemy.position.X + enemy.width / 2), (int)(enemy.position.Y - enemy.height / 8 + y))) // Top right corner
                                { y = 0; }
                                if (ObstacleList[ii].Contains((int)(enemy.position.X - enemy.width / 2), (int)(enemy.position.Y - enemy.height / 8 + y))) // Top Left corner
                                { y = 0; }
                            }

                           
                            // fast enemy trail
                            if(enemy.type == 3)
                            {
                                animation = new Animation(enemy.position, enemy.charTexture, 56 * enemy.currentSprite, 80 * enemy.spriteRow, enemy.width, enemy.height, 1, 200, false, true);
                                zombieBlurAnimations.Add(animation);
                            }

                            // enemy's projected new position
                            enemyPositionX = enemy.position.X + x;
                            enemyPositionY = enemy.position.Y + y;

                            // logic when an enemy moves to a different grid
                            enemy.position.X = enemyPositionX;
                            enemy.position.Y = enemyPositionY;
                            if (enemyPositionX < i * cellSize && i > 0)
                            {
                                enemyList[i, j].Remove(enemy);
                                enemyList[i - 1, j].Add(enemy);
                                --count;
                            }
                            else if (enemyPositionX >= i * cellSize + cellSize)
                            {
                                enemyList[i, j].Remove(enemy);
                                enemyList[i + 1, j].Add(enemy);
                                --count;
                                // change state to indicate zombie moved to a higher cell to. this is done to prevent double movement
                                enemy.state = "MOVED";
                            }
                            else if (enemyPositionY < j * cellSize && j > 0)
                            {
                                enemyList[i, j].Remove(enemy);
                                enemyList[i, j - 1].Add(enemy);
                                --count;
                            }
                            else if (enemyPositionY >= j * cellSize + cellSize)
                            {
                                enemyList[i, j].Remove(enemy);
                                enemyList[i, j + 1].Add(enemy);
                                --count;
                                // change state to indicate zombie moved to a higher cell to. this is done to prevent double movement
                                enemy.state = "MOVED";
                                
                            }
                        }

                        if (checkCollisionPlayerZombie(enemy.position, enemy.width, enemy.height, player.position, player.width, player.height) && !player.invulnerable)
                        {
                            player.changeHitColor();
                            player.lives--;
                            player.invulnerable = true;
                        }

                        ++count;
                    }
                }
            }
            end = DateTime.Now - start;

            if (timer > interval)
                timer = 0f;

            return (float)end.TotalMilliseconds;
        }

        public bool checkCollisionPlayerZombie(Vector2 enemyPos, float enemyWidth, float enemyHeight, Vector2 playerPos, float playerWidth, float playerHeight)
        {

            if (enemyPos.Y >= playerPos.Y-10 && enemyPos.Y <= (playerPos.Y + playerHeight/1.25)) // Zombie Coming from bottom
            {
                if ((enemyPos.X + enemy.width / 1.25) >= playerPos.X && (enemyPos.X + enemy.width / 1.25) <= (playerPos.X + playerWidth+15))
                    return true;
               // else if ((enemyPos.X + enemyWidth) > playerPos.X && (enemyPos.X + enemyWidth) < (playerPos.X + playerWidth/2)) 
               //     return true;
            }
            else if ((enemyPos.Y + enemyHeight) >= playerPos.Y+10 && (enemyPos.Y + enemyHeight) <= (playerPos.Y + playerHeight))
            {
                if ((enemyPos.X + enemy.width / 1.25) >= playerPos.X && (enemyPos.X + enemy.width / 1.25) <= (playerPos.X + playerWidth+15))
                    return true;
               // else if ((enemyPos.X + enemyWidth) > playerPos.X && (enemyPos.X + enemyWidth) < (playerPos.X + playerWidth/2)) // TOP RIGHT CORNER
               //     return true;
            }

            return false;
        }

        public bool checkCell(int i, int j, float x, float y, Enemy enemy)
        {
            // avoid index = -1
            if (i < 0)
                i = 0;
            if (j < 0)
                j = 0;
            //foreach (Enemy currentEnemy in enemyList[i, j])
            for(int iii = 0; iii < enemyList[i, j].Count; ++iii)
            {
                if (iii > 3)
                    return true;

                currentEnemy = enemyList[i, j][iii];

                ++zombieCollisionCount;

                // distance between zombies AFTER next movement. Next movement is multiplied by 2 because somehow it makes it work better lol
                afterMoveDistance = Math.Sqrt(Math.Pow(currentEnemy.position.X - enemy.position.X - (x * collisionScale), 2) + Math.Pow(currentEnemy.position.Y - enemy.position.Y - (y * collisionScale), 2.0));

                if (afterMoveDistance < enemy.collisionRadius / 2 + currentEnemy.collisionRadius / 2)
                {
                    // distance between zombies BEFORE next movement.
                    beforeMoveDistance = Math.Sqrt(Math.Pow(currentEnemy.position.X - enemy.position.X, 2) + Math.Pow(currentEnemy.position.Y - enemy.position.Y, 2.0));
                    // if zombies are too close AFTER moving but not overlapping, don't allow movement, and stop checking
                    if (beforeMoveDistance > afterMoveDistance)
                        return false;
                }
            }

            return true;
        }

        // optimize
        Vector2 deadZombieAngle = new Vector2(-1, 0);
        Vector2 deadZombieAngleRef;
        Vector2 deadZombieLegs;
        Animation nextAnimation;

        // moves bullets and detects collision
        public float bulletCollision(ref bool allowEnemyDeath, ref GameTime gameTime)
        {
            start = DateTime.Now;

            bulletCollisionCount = 0;
            int bulletCount = 0;
            while (bulletCount < bulletList.Count)
            {
                b = bulletList[bulletCount];

                b.move(ref gameTime);

                if (b.position.X < 0 || b.position.X > 1600 || b.position.Y < 0 || b.position.Y > 1200)
                {
                    bulletList.Remove(b);
                    continue;
                }

                if (b.lifeTime > b.maxLifeTime)
                {
                    bulletList.Remove(b);
                    addExplosion(ref b);
                    continue;
                }

                // obstacle collision, except for laser
                if (b.state != 1)
                {
                    bool obstacleCollide = false;
                    for (int i = 0; i < ObstacleList.Length && (b.velocity.X != 0 || b.velocity.Y != 0); i++)
                    {
                        ++bulletCollisionCount;
                        if (ObstacleList[i].Contains((int)(b.position.X), (int)(b.position.Y))) // Bottom right corner
                        {
                            obstacleCollide = true;
                            i = ObstacleList.Length;
                        }
                        else if (ObstacleList[i].Contains((int)(b.position.X), (int)(b.position.Y))) // Bottom Left corner
                        {
                            obstacleCollide = true;
                            i = ObstacleList.Length;
                        }
                    }
                    if (obstacleCollide)
                    {
                        bulletList.Remove(b);
                        addExplosion(ref b);
                        continue;
                    }
                }

                // how many cells around the bullet to check
                checkRadius = (int)Math.Ceiling((double) b.hitRadius / cellSize);

                minX = (int)(b.position.X / cellSize) - checkRadius;
                minY = (int)(b.position.Y / cellSize) - checkRadius;
                if (minX < 0)
                    minX = 0;
                if (minY < 0)
                    minY = 0;

                // check all cells in the area
                for (checkX = minX; checkX < minX + checkRadius * 2 && checkX < arraySize; ++checkX)
                {
                    for (checkY = minY; checkY < minY + checkRadius * 2 && checkY < arraySize; ++checkY)
                    {
                        int zombieCount = 0;
                        ++bulletCollisionCount;
                        while (zombieCount < enemyList[checkX, checkY].Count)
                        {
                            ++bulletCollisionCount;
                            enemy = enemyList[checkX, checkY][zombieCount];

                            // distance between bullets and zombies
                            distance = (float)Math.Sqrt(Math.Pow(b.position.X - enemy.position.X, 2.0) + Math.Pow(b.position.Y - enemy.position.Y, 2.0));
                            if (distance < b.hitRadius / 2 + enemy.collisionRadius / 2)
                            {
                                if (allowEnemyDeath)
                                {
                                    //POWERUP
                                    powerupDrop(enemy);
                                    addScore();

                                    --enemy.lives;

                                    // remove enemy if dead
                                    if (enemy.lives < 1 || b.state == 1)
                                    {
                                        enemyList[checkX, checkY].Remove(enemy);
                                        --zombieCount;
                                        --zombiesAlive;
                                        ++zombiesKilled;
                                        animation = new Animation(enemy.position, enemy.charTexture, 0, 329, 77, 84, 1, 100, false, false);
                                        deadZombieLegs = enemy.position;
                                        deadZombieLegs.Y += 20;
                                        nextAnimation = new Animation(deadZombieLegs, enemy.charTexture, 98, 354, 61, 70, 1, 3000, false, true);
                                        nextAnimation.infinite = true;
                                        if (enemy.type == 2)
                                        {
                                            animation.scale = 1.5f;
                                            nextAnimation.scale = 1.5f;
                                        }
                                        deadZombieAngleRef = enemy.velocity;
                                        float angle = angleVector(ref deadZombieAngleRef, ref deadZombieAngle);
                                        animation.rotation = -angle;
                                        nextAnimation.rotation = -angle;
                                        animation.nextFrame = nextAnimation;
                                        deadZombieAnimations.Add(animation);
                                    }
                                    else
                                    {
                                        enemy.changeHitColor();
                                    }

                                    // do not remove infinite durability bullets
                                    if (b.state != 1)
                                    {
                                        bulletList.Remove(b);
                                        --bulletCount;
                                        // stops for loops
                                        checkY = arraySize;
                                        checkX = arraySize;
                                    }
                                    addExplosion(ref b);
                                    break;
                                }
                            }
                            ++zombieCount;
                        }
                    }
                }

                ++bulletCount;
            }

            end = DateTime.Now - start;
            return (float)end.TotalMilliseconds;
        }

        public void addExplosion(ref Bullet b)
        {
            if (b.state == 2)
            {
                bulletList.Add(new Bullet(b.position, new Vector2(0f, 0f), b.blastTexture, 1, b.blastRadius, 0f, b.blastMaxTime, 0f, b.blastMidPoint));
                animation = new Animation(b.position, 0, 0, 0, 105, 141, 2, 350, true, false);
                animation.scale = 1.25f;
                bulletAnimations.Add(animation);
            }
        }

        //public bool outOfBounds(Rectangle)
        //public void addBullet(ArrayList(Bullet))

        /// <summary>
        /// This method will drop the powerups when a player kills a zombie
        /// </summary>
        /// <param name="e">The enemy to use its location</param>
        private void powerupDrop(Enemy e)
        {
            //Testing powerup drop
            if (powerupList.Count <= MAX_POWERUPS)
            {
                int random = rnd.Next(0, MAX_RANDOM) + 1;
                if (random <= POWERUP_FREQUENCY)
                {
                    random = rnd.Next(0, 5);
                    //random = 4;
                    powerup = new Powerup(texture, random, e.position);
                    powerupList.Add(powerup);
                }
            }
        }


        private void checkPowerupCollision()
        {
            pickedUp = false;
            bool collided = false;
            foreach (Powerup p in powerupList)
            {

                if (player.position.Y > p.position.Y && player.position.Y < (p.position.Y + 80)) // COLLISION WITH HEAD OF PLAYER
                {
                    if ((player.position.X) < (p.position.X + 40) && player.position.X > p.position.X)
                        collided = true;
                    else if ((player.position.X + player.width) > (p.position.X) && (player.position.X + player.width / 4) < (p.position.X - 80))
                        collided = true;
                }
                if ((player.position.Y + player.height / 4) > p.position.Y && (player.position.Y + player.height / 4) < (p.position.Y + 80)) // COLLISION WITH FEET OF PLAYER
                {
                    if ((player.position.X - 20) < (p.position.X + 40) && player.position.X > p.position.X)
                        collided = true;
                    else if ((player.position.X + player.width) > (p.position.X) && (player.position.X + player.width / 4) < (p.position.X - 80))
                        collided = true;
                }
                if (collided)
                {
                    selectWeapon(p);
                    removePowerup.Add(p);
                    pickedUp = true;
                }
                collided = false;
            }
            removePowerups();
        }

        /// <summary>
        /// Creates a new weapon based on the powerup
        /// </summary>
        /// <param name="p">The powerup to get the ID</param>
        private void selectWeapon(Powerup p)
        {
            switch (p.id)
            {
                case 0: player.weapon = new MachineGun(bulletTexture); pickedUpID = p.id;
                    break;
                case 1: player.weapon = new Shotgun(bulletTexture); pickedUpID = p.id;
                    break;
                case 2: player.weapon = new Spread(bulletTexture); pickedUpID = p.id;
                    break;
                case 3: player.weapon = new Laser(laserTexture);
                    break;
                case 4: 
                    bulletList.Add(new Nuke(bulletTexture));
                    animation = new Animation(new Vector2(0,0),1,0,0,1,1,1,2000,false,true);
                    animation.scale = 1600;
                    bulletAnimations.Add(animation);
                    pickedUpID = 4;
                    break;
            }
        }


        /// <summary>
        /// Clears powerups from the map
        /// </summary>
        private void removePowerups()
        {
            foreach (Powerup p in removePowerup)
            {
                powerupList.Remove(p);
            }
            removePowerup.Clear();
        }

        /// <summary>
        /// Returns max number of zombies allowed at one time
        /// </summary>
        /// <returns></returns>
        public int maxZombies()
        {
            return TOTAL_ZOMBIES;
        }

        /// <summary>
        /// Adds score when a player kills a zombie and checks if a life should be added
        /// </summary>
        private void addScore()
        {
            player.score += enemy.points;
            if (player.score % POINTS_FOR_EXTRA_LIFE == 0)
            {
                player.lives++;
                extraLifeSound = true;
            }
        }

        // temp lazy fix
        public void setBulletTexture(Texture2D t, Texture2D lt)
        {
            bulletTexture = t;
            laserTexture = lt;
        }

        public float angleVector(ref Vector2 v1, ref Vector2 v2)
        {
            return (float)(Math.Atan2(v1.X, v1.Y) - Math.Atan2(v2.X, v2.Y));
        }
    }
}